#pragma once
#include "TCP_server.hpp"
#include <memory>
#include "tools.hpp"
#include <functional>
// http协议的相应报文也是一个结构化数据
const std::string glinespace = " ";
const std::string glinesep = "\r\n";
const std::string handsep = ": ";
const std::string temp = "?";

const std::string webroot = "./wwwroot";
const std::string homepage = "index.html";
class Http_Request
{
public:
    Http_Request() : _changeline(glinesep),_Is_Interact(false)
    {
    }
    ~Http_Request()
    {
    }

    void ParseReqLine(std::string &reqline)
    {
        // GET / HTTP/1.1
        std::stringstream ss(reqline);
        ss >> _method >> _uri >> _version;
    }
    // 提供需求报文的反序列化接口

    void Deserialize(std::string &req)
    {
        std::string inbuffer;
        bool ret = Tool::Read_One_Line(req, &inbuffer, glinesep);
        (void)ret;
        LOG(LogLevel::DEBUG) << inbuffer;
        ParseReqLine(inbuffer);
        LOG(LogLevel::DEBUG) << "_method: " << _method;
        LOG(LogLevel::DEBUG) << "_uri: " << _uri;
        LOG(LogLevel::DEBUG) << "_version: " << _version;

        if (_uri == "/")
        {
            // 将_uri设置为默认的首页
            _uri = webroot + _uri + homepage;
        }
        else
        {
            _uri = webroot + _uri;
        }
        auto pos = _uri.find(temp);
        if (pos != std::string::npos)
        {
            // 需要交互：
            _Is_Interact = true;
            // 获取函数key值与参数：
            _parameter = _uri.substr(pos + temp.size());
            _uri = _uri.substr(0, pos);
        }
    }
    std::string Uri()
    {
        return _uri;
    }
    bool Getinteratc()
    {
        return _Is_Interact;
    }
    std::string Getparameter()
    {
        return _parameter;
    }

public:
    std::string _method;
    std::string _uri;
    std::string _version;
    std::unordered_map<std::string, std::string> _handers;
    std::string _changeline;
    std::string _text;

    // 是否需要交互：
    bool _Is_Interact;
    // 动态交互的属性：函数key值+参数
    std::string _parameter;
};

class Http_Responce
{
public:
    Http_Responce() : _changeline(glinesep), _version("HTTP/1.1")
    {
    }
    ~Http_Responce()
    {
    }
    std::string FileType()
    {
        auto pos = _targetfile.rfind(".");
        if (pos == std::string::npos)
        {
            // 说明访问的是首页
            return "text/html";
        }
        std::string suffix = _targetfile.substr(pos);
        if (suffix == ".html" || suffix == ".htm")
            return "text/html";
        else if (suffix == ".jpg")
            return "image/jpeg";
        else if (suffix == "png")
            return "image/png";
        else
            return "";
    }
    void SetHandle(std::string key, std::string value)
    {
        auto pos = _handers.find(key);
        if (pos != _handers.end())
        {
            // 有该报头属性，不做过多操作：
            return;
        }
        // 没有该属性，插入：
        _handers.insert(std::make_pair(key, value));
    }
    bool Setcode(int code)
    {
        _code = code;
        switch (code)
        {
        case 404:
            _desc = "Not Found!!";
            break;
        case 200:
            _desc = "ok";
        case 302:
            _desc = "redir text";
        default:
            break;
        }
        return true;
    }
    void Setargetfile(std::string filename)
    {
        _targetfile = filename;
    }
    bool MakeResponse()
    {
        if (_targetfile == "./wwwroot/favicon.ico")
        {
            return false;
        }
        if (_targetfile == "./wwwroot/redir_text")
        {
            // 进行一次重定向：
            Setcode(302);
            SetHandle("Location", "/image/qiqi.jpg");
            return true;
        }
        bool ok = Tool::Read_File_Content(_targetfile, &_text);
        if (!ok)
        {
            _text = "";
            LOG(LogLevel::INFO) << "客户端访问的文件不存在" << _targetfile;
            // 设置状态码与相关描述：
            Setcode(404);
            // 重新设置targetfile指向404页面
            _targetfile = "./wwwroot/404.html";
            Tool::Read_File_Content(_targetfile, &_text);
            // 获取文件类型：
            std::string type = FileType();
            // 设置两个响应报头的属性：文件大小、文件类型
            SetHandle("Content-Length", std::to_string(_text.size()));
            SetHandle("Content-Type", type);
        }
        else
        {
            Setcode(200);
            // 获取文件类型：
            std::string type = FileType();
            // 设置两个响应报头的属性：文件大小、文件类型
            SetHandle("Content-Length", std::to_string(_text.size()));
            SetHandle("Content-Type", type);
        }
        return true;
    }
    // 提供响应报文的序列化与反序列化接口
    std::string Serialize()
    {
        // 状态行：
        std::string statusline = _version + glinespace + std::to_string(_code) + glinespace + _desc + glinesep;
        // 报头：
        std::string line;
        for (auto &hander : _handers)
        {
            std::string ret = hander.first + handsep + hander.second + glinesep;
            line += ret;
        }

        // 返回整个响应报文：状态行+报头+换行符+正文：
        return statusline + line + _changeline + _text;
    }
    bool SetText(std::string text)
    {
        _text=text;
        return true;
    }
private:
    std::string _version;
    int _code;
    std::string _desc;
    std::unordered_map<std::string, std::string> _handers;

    std::string _changeline;
    std::string _text;

    // 其他属性：
    std::string _targetfile;
};

using http_func_t = std::function<void(Http_Request &req, Http_Responce *resp)>;
class Http
{
public:
    Http(uint16_t port) : _tsvrp(std::make_unique<TcpServer>(port))
    {
    }
    ~Http()
    {
    }
    void HandlerHttpRequest(std::shared_ptr<Socket> ptr, InetAddr client)
    {
        std::string inbuffer;
        int ret = ptr->Recv(&inbuffer);
        // 验证报文的完整性

        // 用需求报文接受并进行反序列化
        Http_Request req;
        req.Deserialize(inbuffer); // 这里我们假设受到了一个完整报文
        // 创建一个响应报文：
        Http_Responce resp;
        // 首先判断是否需要处理动态业务：
        if (req.Getinteratc())
        {
            // 判断业务函数是否已经注册：
            auto pos = actions.find(req.Uri());
            if (pos != actions.end())
            {
                // 已经注册了：
                actions[req.Uri()](req, &resp);
                std::string responce_str = resp.Serialize();

                LOG(LogLevel::DEBUG) << responce_str;

                ptr->Send(responce_str);
            }
            else
            {
                // 没有注册;
                resp.Setcode(302);
                resp.SetHandle("Location", "/404.html");
            }
        }
        else
        {
            resp.Setargetfile(req.Uri());
            resp.MakeResponse();
            std::string responce_str = resp.Serialize();

            LOG(LogLevel::DEBUG) << responce_str;

            ptr->Send(responce_str);
        }
    }
    void Start()
    {
        _tsvrp->Run([this](std::shared_ptr<Socket> ptr, InetAddr client)
                    { this->HandlerHttpRequest(ptr, client); });
    }

    // 提供一个注册函数用来初始化服务器时注册动态业务函数：
    bool Register_Actins(std::string key, http_func_t h)
    {
        key = webroot+ key;
        auto pos = actions.find(key);
        if (pos != actions.end())
        {
            return false;
        }
        actions.insert(std::make_pair(key, h));
        return true;
    }

private:
    std::unique_ptr<TcpServer> _tsvrp;

    // 对应动态业务的函数列表：
    std::unordered_map<std::string, http_func_t> actions;
};